#include "strings.h"
namespace XScript::Memory::Strings
{
	static size_t xscriptcall GetMultiByteToWideByteLength(const char *src)
	{
		size_t src_idx, dest_idx;
		size_t status;
		mbstate_t ps;
		memset(&ps, 0, sizeof(mbstate_t));
		for (src_idx = dest_idx = 0; src[src_idx] != '\0'; )
		{
			status = mbrtowc(NULL, &src[src_idx], MB_LEN_MAX, &ps);
			if (status == static_cast<size_t>(-1))
			{
				return status;
			}
			dest_idx++;
			src_idx += status;
		}
		return dest_idx;
	}
	static size_t xscriptcall GetWideByteToMultiByteLength(const Character *src)
	{
		size_t src_idx, dest_idx;
		size_t status;
		char dummy[MB_LEN_MAX];
		mbstate_t ps;
		memset(&ps, 0, sizeof(mbstate_t));
		for (src_idx = dest_idx = 0; src[src_idx] != L'\0'; )
		{
			status = wcrtomb(dummy, src[src_idx], &ps);
			if (status == static_cast<size_t>(-1))
			{
				return status;
			}
			src_idx++;
			dest_idx += status;
		}
		return dest_idx;
	}
	static void xscriptcall MultiByteToWideByte(const char *src, Character *dest)
	{
		size_t src_idx, dest_idx;
		size_t status;
		mbstate_t ps;
		memset(&ps, 0, sizeof(mbstate_t));
		for (src_idx = dest_idx = 0; src[src_idx] != '\0'; )
		{
			status = mbrtowc(&dest[dest_idx], &src[src_idx], MB_LEN_MAX, &ps);
			dest_idx++;
			src_idx += status;
		}
		dest[dest_idx] = L'\0';
	}
	static void xscriptcall WideByteToMultiByte(const Character *src, char *dest)
	{
		size_t src_idx, dest_idx;
		size_t status;
		mbstate_t ps;
		memset(&ps, 0, sizeof(mbstate_t));
		for (src_idx = dest_idx = 0; src[src_idx] != '\0'; )
		{
			status = wcrtomb(&dest[dest_idx], src[src_idx], &ps);
			src_idx++;
			dest_idx += status;
		}
		dest[dest_idx] = '\0';
	}

	RawStringManager::RawStringManager()
	{

	}

	RawStringManager::~RawStringManager()
	{
		Dispose();
	}

	RawString RawStringManager::CreateFromMultiByte(const char * cstr)
	{
		Character* raw = NewString(GetMultiByteToWideByteLength(cstr));
		MultiByteToWideByte(cstr, raw);
		return raw;
	}

	void RawStringManager::Dispose()
	{
		for (auto it = raw_strings.begin(); it != raw_strings.end(); it++)
		{
			free(*it);
		}
		raw_strings.clear();
	}

	RawString RawStringManager::FindEqual(RawString str)
	{
		for (auto it = raw_strings.begin(); it != raw_strings.end(); it++)
		{
			if (wcscmp(str, *it) == 0)
			{
				return *it;
			}
		}
		return str;
	}

	RawString RawStringManager::Chain(RawString s1, RawString s2)
	{
		Character* string = NewString(wcslen(s1) + wcslen(s2) + 1);
		wcscpy(string, s1);
		wcscat(string, s2);
		return string;
	}

	Character* RawStringManager::NewString(size_t size)
	{
		Character* string = (Character*)malloc((size) * sizeof(Character));
		raw_strings.push_front(string);
		return string;
	}

}